package com.good.webadmin.Controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.dysmsapi20170525.models.SendSmsResponseBody;
import com.auth0.jwt.JWT;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.util.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.good.domain.Utils.RedisUtil;
import com.good.domain.controller.BaseController;
import com.good.domain.entity.AdminRole;
import com.good.domain.entity.AdminUser;
import com.good.domain.models.PageModel;
import com.good.domain.models.PostID;
import com.good.domain.models.Result;
import com.good.domain.models.SmsModel;
import com.good.domain.service.*;
import com.good.webadmin.Models.Audience;
import com.good.webadmin.Models.Params.*;
import com.good.webadmin.Models.TokenUser;
import com.good.webadmin.Service.IJavaWebTokenService;
import com.good.webadmin.Utils.GlobalConfig;
import com.good.webadmin.Utils.SignUtil;
import com.good.webadmin.config.MyException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/webadmin/adminuser")
@Api(tags = "管理员")
public class AdminLoginController extends BaseController {
    @Autowired
    private Audience audience;
    @Autowired
    private IAdminUserService iAdminUserService;
    @Autowired
    private IAdminRoleModuleService iAdminRoleModuleService;
    @Autowired
    private GlobalConfig globalConfig;
    @Autowired
    private IAdminRoleService iAdminRoleService;
    @Autowired
    private IAdminLogService adminLogService;
    @Autowired
    private SignUtil signUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IJavaWebTokenService tokenService;
    @Autowired
    ISmsService iSmsService;

    private final static String DAY_LIMIT_CONTROL = "isv.DAY_LIMIT_CONTROL";
    private final static String SMS_CONTENT_ILLEGAL = "isv.SMS_CONTENT_ILLEGAL";
    private final static String MOBILE_NUMBER_ILLEGAL = "isv.MOBILE_NUMBER_ILLEGAL";
    private final static String BUSINESS_LIMIT_CONTROL = "isv.BUSINESS_LIMIT_CONTROL";

    @GetMapping(value = "/captcha")
    @ApiOperation("图形验证码")
    public void captcha(HttpServletRequest request, HttpServletResponse response) {
        //定义图形验证码的长和宽
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(200, 100);
        String code = lineCaptcha.getCode();
        request.getSession().setAttribute("captcha", code);
        try {
            lineCaptcha.write(response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ApiOperation("管理员登录。keys=username+password")
    public Result login(HttpServletRequest request, @RequestBody LoginUser user) {
//        Object captcha = request.getSession().getAttribute("captcha");
//        if (captcha == null) {
//            return Result.OtherError("请先获取图形验证码");
//        }
//        if (!StringUtils.hasLength(user.getCode()) || !String.valueOf(captcha).equals(user.getCode())) {
//            return Result.OtherError("验证码错误");
//        }
        if (signUtil.check(user.timestamp, user.sign, user.getUserName() + user.getPassWord())) {
            QueryWrapper<AdminUser> queryWrapper=new QueryWrapper<>();
            queryWrapper.like("name",user.getUserName());

            var adminuser = iAdminUserService.getOne(queryWrapper);
            if (adminuser == null) {
                //日志记录
                adminLogService.setAdminLog(null, "[用户名密码错误]", user);
                return OtherError("用户名不正确");
            } else {
                if (adminuser.getState() != 0) {
                    //日志记录
                    adminLogService.setAdminLog(adminuser.getUid(), "[账号未授权,暂无法登陆]", user);
                    return OtherError("账号未授权,暂无法登陆");
                }
                if (adminuser.getLoginError() > 5) {
                    Duration duration = Duration.between(LocalDateTime.now(), adminuser.getUpdateTime());
                    if (duration.toHours() < 2) {
                        //日志记录
                        adminLogService.setAdminLog(adminuser.getUid(), "[登录验证次数过多]", user);
                        return OtherError("登录次数太多,2个小时后再试");
                    }
                }
                String md5Password = audience.getSecretKey() + user.getPassWord();
                md5Password = DigestUtils.md5DigestAsHex(md5Password.getBytes());
                if (adminuser.getPassWord().equals(md5Password)) {
                    adminuser.setLoginError(0);
                    adminuser.setUpdateTime(null);
                    iAdminUserService.updateById(adminuser);
                    JSONObject userObject = new JSONObject();
                    userObject.put("id", adminuser.getId());
                    userObject.put("pic", adminuser.getImageHead());
                    userObject.put("nickName", adminuser.getNickName());
                    userObject.put("mobile", adminuser.getMobile());
                    userObject.put("email", adminuser.getEmail());
                    String token = tokenService.sign(String.valueOf(adminuser.getId()), userObject.toJSONString());
                    String role = adminuser.getRole();
                    if (StringUtils.hasLength(role)) {
                        String[] roles = role.split(",");
                        QueryWrapper<AdminRole> queryWrapperRole = new QueryWrapper<>();
                        queryWrapperRole.in("id", roles);
                        queryWrapperRole.select("id", "role_name");
                        var adminRoles = iAdminRoleService.listMaps(queryWrapperRole);
                        userObject.put("role", adminRoles);

                        var adminModule = iAdminRoleModuleService.getModleByRole(role);
                        userObject.put("module", adminModule);
                    }
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("token", token);
                    jsonObject.put("expired", audience.getExpiresSecond());
                    jsonObject.put("user", userObject);
                    //日志记录
                    adminLogService.setAdminLog(adminuser.getUid(), "[登录成功]", user);
                    return Success(jsonObject);
                } else {
                    adminuser.setLoginError(adminuser.getLoginError() + 1);
                    adminuser.setUpdateTime(null);
                    iAdminUserService.updateById(adminuser);
                    //日志记录
                    adminLogService.setAdminLog(adminuser.getUid(), "[密码错误]", user);
                    return OtherError("密码错误");
                }
            }
        } else {
            return SignError();
        }
    }

    @PostMapping("add")
    @ApiOperation(value = "注册用户", notes = "keys为手机号")
    public Result signUp(MultipartFile file, AdminUserSignUpModel model) {
        if (model.getMobile() == null || StringUtils.isEmpty(model.getNickName()) || StringUtils.isEmpty(model.getEmail())) {
            return NoParamError("缺少参数");
        }
        if (!signUtil.check(model.getTimestamp(), model.getSign(), String.valueOf(model.getMobile()))) {
            return SignError();
        }
        QueryWrapper<AdminUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", model.getUserName()).or().eq("mobile", model.getMobile()).or().eq("email", model.getEmail());
        List<AdminUser> list = iAdminUserService.list(queryWrapper);
        if (!CollectionUtils.isEmpty(list)) {
            return OtherError("用户名、手机号、邮箱不能重复");
        }
        AdminUser adminUser = new AdminUser();
        String md5Password = audience.getSecretKey() + model.getPassWord();
        md5Password = DigestUtils.md5DigestAsHex(md5Password.getBytes());
        adminUser.setPassWord(md5Password);
        adminUser.setNickName(model.getNickName());
        adminUser.setUserName(model.getUserName());
        adminUser.setUid(0l);
        adminUser.setEmail(model.getEmail());
        adminUser.setMobile(model.getMobile());
        adminUser.setState(-1);
        if (file != null && !StringUtils.isEmpty(file.getOriginalFilename())) {
            String fileName = file.getOriginalFilename();
            String filePath = UUID.randomUUID().toString().replaceAll("-", "") + System.currentTimeMillis() + "." + fileName.substring(fileName.lastIndexOf(".") + 1);
            File uploadFile = new File(globalConfig.getUserFaceFilePath() + filePath);
            try {
                file.transferTo(uploadFile);
                adminUser.setImageHead(filePath);
            } catch (Exception e) {
                log.error("头像上传失败,msg{}", e.getMessage());
                return Error500("头像上传失败");
            }
        }
        boolean isSave = iAdminUserService.save(adminUser);
        if (isSave) {
            return Success(adminUser);
        } else {
            return Error500("账号创建失败");
        }
    }

    @PostMapping("retrieve-password-send")
    @ApiOperation(value = "密码找回发送验证码", notes = "keys为手机号")
    public Result retrievePasswordSend(@RequestBody SmsModel model) {
        if (model.getMobile()==null) {
            return NoParamError("缺少手机号");
        }
        if (!signUtil.check(model.getTimestamp(), model.getSign(), String.valueOf(model.getMobile()))) {
            return SignError();
        }
        QueryWrapper<AdminUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", model.getMobile());
        AdminUser one = iAdminUserService.getOne(queryWrapper);
        if (one == null) {
            return OtherError("账号不存在");
        }
        String smsCode = createSmsCode();
        try {
            SendSmsResponseBody sendSmsResponseBody = iSmsService.sendSmsCode(String.valueOf(model.getMobile()), smsCode);
            if (!"OK".equals(sendSmsResponseBody.getCode())) {
                if (DAY_LIMIT_CONTROL.equals(sendSmsResponseBody.getCode())) {
                    return OtherError("短信获取已达今日最大次数");
                }
                if (SMS_CONTENT_ILLEGAL.equals(sendSmsResponseBody.getCode())) {
                    log.error("短信内容包含禁止发送内容 mobile:[{}]", model.getMobile());
                    return OtherError("短信内容包含禁止发送内容");
                }
                if (MOBILE_NUMBER_ILLEGAL.equals(sendSmsResponseBody.getCode())) {
                    log.error("手机号码格式错误 mobile:[{}]", model.getMobile());
                    return OtherError( "手机号码格式错误");
                }
                if (BUSINESS_LIMIT_CONTROL.equals(sendSmsResponseBody.getCode())) {
                    log.error("短信验证过于频繁 mobile:[{}]", model.getMobile());
                    return OtherError( "短信验证过于频繁");
                }
                return OtherError(sendSmsResponseBody.getMessage());
            }
        } catch (Exception e) {
            log.error("验证码发送失败,msg:{}", e.getMessage());
            return OtherError("验证码发送异常请稍后再试!");
        }
        //5.写入缓存 key为模板key+_+mobile
        redisUtil.set(RedisUtil.ADMIN_RETRIEVE_CODE + "_" + model.getMobile(), smsCode,(long) RedisUtil.MOBILE_REGISTER_CODE_LIVE, TimeUnit.SECONDS);
        log.info("验证码已发送 mobile[{}],code[{}]", model.getMobile(), smsCode);
        return Success();
    }

    @PostMapping("retrieve-password-check")
    @ApiOperation(value = "密码找回", notes = "keys为手机号")
    public Result retrievePasswordCheck(@RequestBody AdminRetrievePasswordModel model) {
        if (!signUtil.check(model.getTimestamp(), model.getSign(), String.valueOf(model.getMobile()))) {
            return SignError();
        }
        Object oldCode = redisUtil.get(RedisUtil.ADMIN_RETRIEVE_CODE + "_" + model.getMobile());
        if (oldCode == null) {
            return OtherError("当前验证码已过期,请重新获取");
        }
        boolean maxVerify = redisUtil.isMaxVerify(RedisUtil.ADMIN_RETRIEVE_VERIFY_TIMES + "_" + model.getMobile(), 5);
        if (maxVerify) {
            return OtherError("验证次数过多");
        }
        if (model.getCode().equals(String.valueOf(oldCode))) {
            redisUtil.remove(RedisUtil.ADMIN_RETRIEVE_CODE + "_" + model.getMobile());
            redisUtil.remove(RedisUtil.ADMIN_RETRIEVE_VERIFY_TIMES + "_" + model.getMobile());
            return Success();
        } else {
            return OtherError("验证码错误");
        }
    }

    @PostMapping("retrieve-password")
    @ApiOperation(value = "密码找回", notes = "keys为手机号")
    public Result retrievePassword(@RequestBody AdminRetrieveModel model) {
        if (!signUtil.check(model.getTimestamp(), model.getSign(), String.valueOf(model.getMobile()))) {
            return SignError();
        }
        QueryWrapper<AdminUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", model.getMobile());
        AdminUser one = iAdminUserService.getOne(queryWrapper);
        if (one == null) {
            return OtherError("用户不存在");
        }
        String md5Password = audience.getSecretKey() + model.getPassword();
        md5Password = DigestUtils.md5DigestAsHex(md5Password.getBytes());
        UpdateWrapper<AdminUser> adminUserUpdateWrapper = new UpdateWrapper<>();
        adminUserUpdateWrapper.eq("id", one.getId()).set("pass_word", md5Password);
        iAdminUserService.update(adminUserUpdateWrapper);
        //日志记录
        adminLogService.setAdminLog(one.getUid(), "[找回密码成功]", model);
        return Success();
    }

    /**
     * 随机生成4位验证码
     *
     * @return 4位验证码字符串
     */
    private String createSmsCode() {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 4; i++) {
            stringBuilder.append(new Random().nextInt(10));
        }
        return stringBuilder.toString();
    }

    @RequestMapping(value = "/register", method = RequestMethod.POST)
    @ApiOperation("添加管理员")
    public Result Register(TokenUser tokenUser, MultipartFile file, String userName, String passWord, String email, Long mobile, String role, String nickName) {
        QueryWrapper<AdminUser>queryWrapper=new QueryWrapper<>();
        queryWrapper.like("nick_name",userName).like("mobile",mobile);
        AdminUser adminUser = iAdminUserService.getOne(queryWrapper);
        if (adminUser != null) {
            return OtherError("用户名和手机号不能重复");
        } else {
            adminUser = new AdminUser();
            String md5Password = audience.getSecretKey() + passWord;
            md5Password = DigestUtils.md5DigestAsHex(md5Password.getBytes());
            adminUser.setPassWord(md5Password);
            adminUser.setNickName(nickName);
            adminUser.setUserName(userName);
            adminUser.setUid(tokenUser.getUserId());
            adminUser.setRole(role);
            adminUser.setEmail(email);
            adminUser.setMobile(mobile);
            if (file != null && !StringUtils.isEmpty(file.getOriginalFilename())) {
                String fileName = file.getOriginalFilename();
                String filePath = UUID.randomUUID().toString().replaceAll("-", "") + System.currentTimeMillis() + "." + fileName.substring(fileName.lastIndexOf(".") + 1);
                File uploadFile = new File(globalConfig.getUserFaceFilePath() + filePath);
                try {
                    file.transferTo(uploadFile);
                    adminUser.setImageHead(filePath);
                } catch (Exception e) {
                    log.error("头像上传失败,msg{}", e.getMessage());
                    return Error500("头像上传失败");
                }
            }
            boolean isSave = iAdminUserService.save(adminUser);
            if (isSave) {
                return Success(adminUser);
            } else {
                return Error500("添加管理员错误");
            }
        }

    }

    @ApiOperation("刷新token. keys=ererr")
    @RequestMapping(value = "/refreshtoken", method = RequestMethod.POST)
    public Result RefreshToken(@RequestBody ParRefreshToken parRefreshToken) {
        if (signUtil.check(parRefreshToken.getTimestamp(), parRefreshToken.getSign(), "ererr")) {
            try {
                var userId = JWT.decode(parRefreshToken.getToken()).getIssuer();
                String newToken = token(userId, parRefreshToken.getToken());
                if (StringUtils.isEmpty(newToken)) {
                    throw new MyException(401, "用户不存在");
                } else {
                    return Success(newToken);
                }
            } catch (Exception e) {
                log.error(e.getMessage());
                e.printStackTrace();
                if (e.getMessage().substring(0, 21).equals("The Token has expired")) {
                    var userId = JWT.decode(parRefreshToken.getToken()).getIssuer();
                    String newToken = token(userId, parRefreshToken.getToken());
                    if (newToken.equals("")) {
                        throw new MyException(401, "用户不存在");
                    } else {
                        return Success(newToken);
                    }
                } else {
                    throw new MyException(401, e.getMessage());
                }

            }
        } else {
            return SignError();
        }
    }

    private String token(String UserId, String token) {
        AdminUser adminuser = iAdminUserService.getById(UserId);
        if (adminuser != null) {
            JSONObject userObject = new JSONObject();
            userObject.put("id", adminuser.getId());
            userObject.put("pic", adminuser.getImageHead());
            userObject.put("nickName", adminuser.getNickName());

            String newToken = tokenService.sign(String.valueOf(adminuser.getId()), userObject.toJSONString());

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("token", newToken);
            jsonObject.put("expired", audience.getExpiresSecond());

            return newToken;
        } else {
            return "";
        }
    }

    @PostMapping("editUser")
    @ApiOperation("修改管理员")
    public Result EditUser(TokenUser tokenUser, @RequestBody ParEditAdminUser parEditAdminUser) {
        AdminUser adminUser = iAdminUserService.getById(parEditAdminUser.getId());
        if (adminUser == null) {
            return NoDataError();
        } else {
            adminUser.setRole(parEditAdminUser.getRole());
            adminUser.setUid(tokenUser.getUserId());
            adminUser.setUpdateTime(null);
            adminUser.setState(0);
            if (iAdminUserService.updateById(adminUser)) {
                return Success("修改成功");
            } else {
                return Error500("修改用户失败");
            }
        }
    }

    @PostMapping("del")
    @ApiOperation("删除管理员")
    public Result Del(TokenUser tokenUser, @RequestBody PostID postID) {
        AdminUser adminUser = iAdminUserService.getById(postID.getId());
        if (adminUser == null) {
            return NoDataError();
        } else {
            String imageHead = adminUser.getImageHead();
            File file1 = new File(globalConfig.getUserFaceFilePath() + imageHead);
            if (file1.exists()) {
                file1.delete();
            }
            if (iAdminUserService.removeById(postID.getId())) {
                return Success("删除成功");
            } else {
                return Error500("删除失败");
            }

        }

    }

    @PostMapping("ListAdmin")
    @ApiOperation("管理员列表")
    @IUserLoginToken
    public Result ListAdmin(@RequestBody PageModel model) {
        QueryWrapper<AdminUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("id", "uid", "user_name", "image_head", "mobile", "email", "nick_name", "insert_time", "role", "state");
        IPage<AdminUser> page = new Page<>(model.getPageNum(), model.getPageSize());
        IPage<AdminUser> result = iAdminUserService.page(page, queryWrapper);
        return Success(result);
    }

    @PostMapping("MyInfo")
    @ApiOperation("我的信息")

    public Result MyInfo(TokenUser tokenUser) {
        QueryWrapper<AdminUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", tokenUser.getUserId());
        queryWrapper.select("user_name", "image_head", "mobile", "email", "nick_name");
        var my = iAdminUserService.getMap(queryWrapper);
        return Success(my);
    }

    @PostMapping("EditMyInfo")
    @ApiOperation("修改我的信息")
    public Result EditMyInfo(TokenUser tokenUser, MultipartFile file, String nickName, String email, Long mobile) {
        UpdateWrapper<AdminUser> queryWrapper = new UpdateWrapper<>();
        queryWrapper.eq("id", tokenUser.getUserId());
        AdminUser adminUser = new AdminUser();
        adminUser.setNickName(nickName);
        adminUser.setEmail(email);
        adminUser.setMobile(mobile);

        if (file != null && !StringUtils.isEmpty(file.getOriginalFilename())) {
            //删除原头像
            AdminUser user = iAdminUserService.getById(tokenUser.getUserId());
            String imageHead = user.getImageHead();
            File file1 = new File(globalConfig.getUserFaceFilePath() + imageHead);
            if (file1.exists()) {
                file1.delete();
            }
            //上传新头像
            String fileName = file.getOriginalFilename();
            String filePath = UUID.randomUUID().toString().replaceAll("-", "") + System.currentTimeMillis() + "." + fileName.substring(fileName.lastIndexOf(".") + 1);
            File uploadFile = new File(globalConfig.getUserFaceFilePath() + filePath);
            try {
                file.transferTo(uploadFile);
                adminUser.setImageHead(filePath);
            } catch (IOException e) {
                log.error("头像上传失败,msg{}", e.getMessage());
                return Error500("头像上传失败");
            }
        }
        if (iAdminUserService.update(adminUser, queryWrapper)) {
            return Success(adminUser);
        } else {
            return OtherError("修改失败");
        }
    }

    @PostMapping("EditPassWord")
    @ApiOperation("修改密码")
    public Result EditPassWord(TokenUser tokenUser, @RequestBody ParEditPassword parEditUser) {

        AdminUser adminUser = iAdminUserService.getById(tokenUser.getUserId());
        if (adminUser == null) {
            return OtherError("没有这个用户");
        } else {
            String md5Password = audience.getSecretKey() + parEditUser.getOld_passWord();
            md5Password = DigestUtils.md5DigestAsHex(md5Password.getBytes());
            if (adminUser.getPassWord().equals(md5Password)) {
                QueryWrapper<AdminUser> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", tokenUser.getUserId());
                adminUser = new AdminUser();
                md5Password = audience.getSecretKey() + parEditUser.getPassWord();
                md5Password = DigestUtils.md5DigestAsHex(md5Password.getBytes());
                adminUser.setPassWord(md5Password);

                if (iAdminUserService.update(adminUser, queryWrapper)) {
                    return Success("修改成功");
                } else {
                    return Error500("修改失败");
                }

            } else {
                return OtherError("密码不正确");
            }
        }


    }
    @PostMapping("getInfo")
    @ApiOperation("根据id查询管理员信息")
    @IUserLoginToken
    public  Result getInfo(@RequestBody PostID postID){
        QueryWrapper<AdminUser> queryWrapper=new QueryWrapper<>();
        queryWrapper.select("nickName","imageHead","mobile","email");
        queryWrapper.eq("id",postID.getId());
        return Success(iAdminUserService.getById(postID.getId()));
    }
}
